package com.asdc.autoscanfiles.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.max.Max;
import org.elasticsearch.search.aggregations.metrics.max.MaxAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.asdc.autoscanfiles.entity.EsResultDto;
import com.asdc.autoscanfiles.page.Page;
import com.asdc.autoscanfiles.repository.EsResultRepository;
import com.asdc.autoscanfiles.utils.StaticUtils;

import static org.elasticsearch.index.mapper.AllFieldMapper.Defaults.INDEX_NAME;

@Service
public class EsResultService {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private EsResultRepository esResultRepository;
    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;
    
    /**
     * 获取ES中最大的ID
     * @return
     */
    public int getMaxIdFromES() {
    	MaxAggregationBuilder mb = AggregationBuilders.max("max_id").field("id");
        // 设置查询字段
        SearchResponse response = elasticsearchTemplate.getClient().prepareSearch(INDEX_NAME)
                .addAggregation(mb).execute().actionGet();
        Max avg = response.getAggregations().get("max_id");
        int id = (int)avg.getValue();
        return id;
    }
    
    /**
     * 保存Mysql数据导ES
     */
    public void saveToEs() {
        Long begin = System.currentTimeMillis();
        
        int id = this.getMaxIdFromES();
        if(id<0){
            id=0;//ES没有数据时，返回的value小于0
        }
        logger.info("本次ES导入开始的id为==" + id);

        // 查询mysql增量总计
        String number = "SELECT count(id) as num FROM qxj.img_file where id > '"
                + id + "'";
        Map<String, Object> map = jdbcTemplate.queryForMap(number);

        if (Integer.parseInt(map.get("num").toString()) != 0) {
            int i = 0;
            for (int i1 = 0; i1 < Integer.parseInt(map.get("num").toString()); i1 = i1 + 10000) {
                // 获取数据库中增量
                StringBuffer sql = new StringBuffer("SELECT i.id, i.level1, ");
                sql.append("i.level2, i.level3, ");
                sql.append("i.begin_date, i.end_date, i.element_type, ");
                sql.append(
                        "i.area_number, i.area_name, i.file_name, i.type, i.new_path ,i.type_value AS typeValue ,i.sheng as sheng, i.province_code, i.province_name ");
                sql.append("FROM qxj.img_file i ");
                sql.append("WHERE i.id > ").append(id);
                sql.append(" order by id LIMIT ").append(i1).append(",10000");
                List<EsResultDto> list = jdbcTemplate.query(sql.toString(),
                        new BeanPropertyRowMapper<EsResultDto>(EsResultDto.class));
                if (!CollectionUtils.isEmpty(list)) {
                    for (EsResultDto dto : list) {
                        dto.setElementName(StaticUtils.getElementName(dto.getElementType()));
                        dto.setLevel1Name(StaticUtils.getLevel1Name(dto.getLevel1()));
                        dto.setLevel2Name(StaticUtils.getLevel2Name(dto.getLevel2()));
                        dto.setLevel3Name(StaticUtils.getLevel3Name(dto.getLevel3()));
                    }
                }
                if(logger.isInfoEnabled()) {
                	logger.info("es: query from db using "+(System.currentTimeMillis()-begin));
                }
                esResultRepository.saveAll(list);
            }
        }
        logger.info("本次ES导入用时：" + String.valueOf(System.currentTimeMillis() - begin));
    }

    /**
     * 保存单个对象
     *
     * @param productDocuments
     */
    public void save(EsResultDto... productDocuments) {
        elasticsearchTemplate.putMapping(EsResultDto.class);
        if (productDocuments.length > 0) {
            logger.info("【保存索引】：{}", esResultRepository.saveAll(Arrays.asList(productDocuments)));
        }
    }

    /**
     * 根据id删除
     *
     * @param id
     */
    public void delete(Integer id) {
        esResultRepository.deleteById(id);
    }

    /**
     * 删除所有
     */
    public void deleteAll() {
        esResultRepository.deleteAll();
    }

    /**
     * 根据id查询
     *
     * @param id
     * @return
     */
    public EsResultDto getById(Integer id) {
        return esResultRepository.findById(id).get();
    }

    /**
     * 查询所有
     *
     * @return
     */
    public List<EsResultDto> getAll() {
        List<EsResultDto> list = new ArrayList<>();
        esResultRepository.findAll().forEach(list::add);
        return list;
    }

    /**
     * 高亮显示
     */
    public List<Map<String, Object>> queryHit(String keyword, String indexName,
                                              String... fieldNames) {
        // 构造查询条件,使用标准分词器.
        QueryBuilder matchQuery = createQueryBuilder(keyword, fieldNames);
        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlightBuilder = createHighlightBuilder(fieldNames);
        // 设置查询字段
        SearchResponse response = elasticsearchTemplate.getClient().prepareSearch(indexName)
                .setQuery(matchQuery)
                .highlighter(highlightBuilder)
                .setSize(10000) // 设置一次返回的文档数量，最大值：10000
                .get();

        // 返回搜索结果
        SearchHits hits = response.getHits();

        return getHitList(hits);
    }

    /**
     * 高亮显示，返回分页
     */
    public Page<Map<String, Object>> queryHitByPage(int pageNo, int pageSize, String keyword,
                                                    String indexName, String... fieldNames) {
        // 构造查询条件,使用标准分词器.
        QueryBuilder matchQuery = createQueryBuilder(keyword, fieldNames);

        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlightBuilder = createHighlightBuilder(fieldNames);

        // 设置查询字段
        SearchResponse response = elasticsearchTemplate.getClient().prepareSearch(indexName)
                .setQuery(matchQuery)
                .highlighter(highlightBuilder)
                .setFrom((pageNo - 1) * pageSize)
                .setSize(pageNo * pageSize) // 设置一次返回的文档数量，最大值：10000
                .get();

        // 返回搜索结果
        SearchHits hits = response.getHits();
        Long totalCount = hits.getTotalHits();
        Page<Map<String, Object>> page = new Page<>(pageNo, pageSize, totalCount.intValue());
        page.setList(getHitList(hits));
        return page;
    }

    /**
     * 处理高亮结果
     */
    private List<Map<String, Object>> getHitList(SearchHits hits) {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map;
        for (SearchHit searchHit : hits) {
            map = new HashMap<>();
            // 处理源数据
            map.put("source", searchHit.getSourceAsMap());
            // 处理高亮数据
            Map<String, Object> hitMap = new HashMap<>();
            searchHit.getHighlightFields().forEach((k, v) -> {
                String hight = "";
                for (Text text : v.getFragments())
                    hight += text.string();
                hitMap.put(v.getName(), hight);
            });
            map.put("highlight", hitMap);
            list.add(map);
        }
        return list;
    }

    /**
     * 构造查询条件
     */
    private QueryBuilder createQueryBuilder(String keyword, String... fieldNames) {
        // 构造查询条件,使用标准分词器.
        return QueryBuilders.multiMatchQuery(keyword, fieldNames) // matchQuery(),单字段搜索
                .operator(Operator.OR);
    }

    /**
     * 构造高亮器
     */
    private HighlightBuilder createHighlightBuilder(String... fieldNames) {
        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                .preTags("<span style='color:red'>")
                .postTags("</span>");

        // 设置高亮字段
        for (String fieldName : fieldNames)
            highlightBuilder.field(fieldName);

        return highlightBuilder;
    }

    /**
     * 删除索引
     */
    public void deleteIndex(String indexName) {
        elasticsearchTemplate.deleteIndex(indexName);
    }

    public Page<Map<String, Object>> findByLevelAndDate(String level1, String level2, String sheng,
                                                        String beginDate, String beginDate1, String searchString, String[] fieldNames,
                                                        int pageNo, int pageSize, String indexName) {

        // 组合查询条件
        BoolQueryBuilder matchQuery = QueryBuilders.boolQuery();

        if (!StringUtils.isEmpty(level1)) {
            matchQuery.must(QueryBuilders.matchQuery("level2Name", level1));
        }
        if (!StringUtils.isEmpty(level2)) {
            matchQuery.must(QueryBuilders.matchQuery("level3Name", level2));
        }
        if (!StringUtils.isEmpty(sheng)) {
            matchQuery.must(QueryBuilders.matchQuery("sheng", sheng));
        }
        if (!StringUtils.isEmpty(searchString)) {
            matchQuery.must(QueryBuilders.multiMatchQuery(searchString, fieldNames));
        }
        if (!StringUtils.isEmpty(beginDate) && !StringUtils.isEmpty(beginDate1)) {
            matchQuery.must(QueryBuilders.rangeQuery("beginDate").lte(beginDate1).gte(beginDate));
        } else if (!StringUtils.isEmpty(beginDate) && StringUtils.isEmpty(beginDate1)) {
            matchQuery.must(QueryBuilders.rangeQuery("beginDate").gte(beginDate));
        } else if (StringUtils.isEmpty(beginDate) && !StringUtils.isEmpty(beginDate1)) {
            matchQuery.must(QueryBuilders.rangeQuery("beginDate").lte(beginDate1));
        }

        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlightBuilder = createHighlightBuilder(fieldNames);
        // 设置查询字段
        SearchResponse response = elasticsearchTemplate.getClient().prepareSearch(indexName)
                .setQuery(matchQuery)
                .highlighter(highlightBuilder)
                .setFrom((pageNo - 1) * pageSize)
                .setSize(pageSize) // 设置一次返回的文档数量，最大值：10000
                .get();

        // 返回搜索结果
        SearchHits hits = response.getHits();
        Long totalCount = hits.getTotalHits();
        Page<Map<String, Object>> page = new Page<>(pageNo, pageSize, totalCount.intValue());
        page.setList(getHitList(hits));
        return page;
    }

}
